package cn.sczc.jh.client.config;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.sczc.jh.client.service.sys.UserService;

@Configuration
public class ShiroConfig {
	@Autowired
	private UserService userService;
	

	// Filter工厂，设置对应的过滤条件和跳转条件
	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		SecurityUtils.setSecurityManager(securityManager);  
		
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		Map<String, String> map = new HashMap<>();
		// 登出
		map.put("/logout.action", "logout");
//        map.put("/static/**", "anon");
		map.put("/api/**", "anon");
		map.put("/css/**", "anon");
		map.put("/fonts/**", "anon");
		map.put("/icons/**", "anon");
		map.put("/images/**", "anon");
		map.put("/js/**", "anon");
		map.put("/lib/**", "anon");
		map.put("/mapIcon/**", "anon");
		map.put("/", "anon");
		// 对所有用户认证
		map.put("/**", "authc");
		// 登录
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 首页
		shiroFilterFactoryBean.setSuccessUrl("/index");
		// 错误页面，认证不通过跳转
		shiroFilterFactoryBean.setUnauthorizedUrl("/error");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
		return shiroFilterFactoryBean;
	}
	
	// 自定义的Realm
	@Bean("authRealm")
	public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher matcher) {
		AuthRealm authRealm = new AuthRealm(this.userService);
		// 这边可以选择是否将认证的缓存到内存中，现在有了这句代码就将认证信息缓存的内存中了
		authRealm.setCacheManager(new MemoryConstrainedCacheManager());
		// 最简单的情况就是明文直接匹配，然后就是加密匹配，这里的匹配工作则就是交给CredentialsMatcher来完成
		authRealm.setCredentialsMatcher(matcher);
		return authRealm;
	}

	@Bean(name = "sessionManager")
	public DefaultWebSessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		// 设置session过期时间1800s
		sessionManager.setGlobalSessionTimeout(1800000L);
		return sessionManager;
	}

	// 权限管理，配置主要是Realm的管理认证
	@Bean("securityManager")
	public SessionsSecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
		// 这个DefaultWebSecurityManager构造函数,会对Subject，realm等进行基本的参数注入
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(authRealm);// 往SecurityManager中注入Realm，代替原本的默认配置
		manager.setSessionManager(sessionManager());
		return manager;
	}

	/*
	 * Realm在验证用户身份的时候，要进行密码匹配
	 * 最简单的情况就是明文直接匹配，然后就是加密匹配，这里的匹配工作则就是交给CredentialsMatcher来完成
	 * 支持任意数量的方案，包括纯文本比较、散列比较和其他方法。除非该方法重写，否则默认值为
	 */
	@Bean("credentialMatcher")
	public CredentialMatcher credentialMatcher() {
		return new CredentialMatcher();
	}

	/*
	 * 以下AuthorizationAttributeSourceAdvisor,
	 * DefaultAdvisorAutoProxyCreator两个类是为了支持shiro注解
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Qualifier("securityManager") SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager);
		return advisor;
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
		return creator;
	}

	@Bean(name = "shiroDialect")
	public ShiroDialect shiroDialect() {
		return new ShiroDialect();
	}
}
